package com.jeasonzhao.commons.parser.expression;

import java.lang.reflect.Method;

import com.jeasonzhao.commons.utils.DataTypes;

public class MethodFunctionSign implements IMethodDefination
{
    private Method m_method = null;
    private String m_strInitName = null;
    private String m_strName = null;
    private DataTypes[] m_parameters = null;
    private Object m_instance = null;
    private DataTypes m_returnDataTypes = DataTypes.OBJECT;
    public MethodFunctionSign(Object objInstance,Method method,String strName)
    {
        m_method = method;
        m_instance = objInstance;
        this.init();
        m_strName = strName == null || strName.trim().length() < 1 ? m_strInitName : strName;
    }

    private void init()
    {
        if(null == m_method)
        {
            return;
        }
        m_strInitName = m_method.getName();
        m_returnDataTypes = DataTypes.from(m_method.getReturnType());
        Class<?> [] cls = m_method.getParameterTypes();
        m_parameters = cls == null || cls.length < 1 ? null : new DataTypes[cls.length];
        for(int n = 0;cls != null && n < cls.length;n++)
        {
            m_parameters[n] = DataTypes.from(cls[n]);
        }
    }

    public String toString()
    {
        return m_strName + "@" + m_method.getDeclaringClass().getName();
    }

    public ValuePair invoke(ValuePair[] params)
        throws EvalException
    {
        Object[] realParam = null;
        if(m_parameters != null)
        {
            if(params == null || params.length < m_parameters.length)
            {
                throw new EvalException("More parameters needed for invoking" + this.getFunctionName()
                                        + ", expected " + m_parameters.length + " but only" +
                                        (null == params ? 0 : params.length));
            }
            realParam = new Object[m_parameters.length];
            for(int nParam = 0;nParam < realParam.length;nParam++)
            {
                try
                {
                    realParam[nParam] = params[nParam] == null ? null : params[nParam].getRealData(m_parameters[nParam]);
                }
                catch(Exception ex)
                {
                    throw new EvalException("Invoking " + this.getFunctionName() + " Error "
                                            + (nParam + 1) + " cast error," + ex.getMessage(),ex);
                }
            }
        }
        try
        {
            this.m_method.setAccessible(true);
            Object obj = m_method.invoke(this.m_instance,realParam);
            return new ValuePair(obj,m_returnDataTypes == null ? DataTypes.VOID : m_returnDataTypes);
        }
        catch(Exception ex)
        {
            throw new EvalException("Invoking " + this.toString() + " error," + ex.getMessage(),ex);
        }
    }

    public String getFunctionName()
    {
        return m_strName;
    }

    public DataTypes getReturnType()
    {
        return this.m_returnDataTypes;
    }

    public DataTypes[] getParametersType()
    {
        if(null == m_parameters)
        {
            return null;
        }
        DataTypes[] ret = new DataTypes[m_parameters.length];
        for(int n = 0;n < m_parameters.length;n++)
        {
            ret[n] = m_parameters[n];
        }
        return ret;
    }
}
